package seatiger.tomcat.catalina.core;

import org.apache.commons.digester.Digester;
import seatiger.tomcat.catalina.*;
import seatiger.tomcat.catalina.startup.ContextRuleSet;
import seatiger.tomcat.util.StringManager;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 部署器
 */
public class StandardHostDeployer implements Deployer {

    protected static StringManager sm = StringManager.getManager(Constants.PACKAGE_CORE);

    private StandardHost host;

    private Digester digester = null;

    private ContextRuleSet contextRuleSet = null;

    public StandardHostDeployer(StandardHost host){
        this.host = host;
    }

    /**
     * 和这个Host关联的Context
     */
    private Context context = null;





    @Override
    public void install(URL config) throws IOException {
        if (config == null){
            throw new IllegalArgumentException
                    (sm.getString("standardHost.configRequired"));
        }
        try (InputStream stream = config.openStream()){
            context = null;
            Digester digester = createDigester();
            digester.clear();
            digester.push(this);
            digester.parse(stream);
        }catch (Exception e){
            host.log(sm.getString("standardHost.installError"), e);
        }
    }

    private Digester createDigester() {
        digester = Optional.ofNullable(digester).orElseGet(() -> {
            Digester digester = new Digester();
            contextRuleSet = new ContextRuleSet("");
            digester.addRuleSet(contextRuleSet);
            return digester;
        });
        return digester;
    }

    /**
     * 添加一个孩子 Context容器到Host容器中取
     * @param child
     */
    public void addChild(Container child){
        context = (Context) child;
        String contextPath = context.getPath();
        //校验在这个Host容器中相同的Context只能有一个
        validateContext(contextPath, c -> c != null ? sm.getString("standardHost.pathUsed") : null);
        host.addChild(child);
    }

    @Override
    public void install(String contextPath, URL dirUrl) throws IOException{
        if (dirUrl == null){
            throw new IllegalArgumentException(sm.getString("standardHost.warRequired"));
        }
        host.log(sm.getString("standardHost.installing",contextPath, dirUrl.toString()));
        String docBase = dirUrl.getPath();
        //手动创建Context对象
        try {
            Class<Context> clazz = (Class<Context>) Class.forName(host.getContextClass());
            Context context = clazz.newInstance();
            context.setDocBase(docBase);
            context.setPath(contextPath);
            if (context instanceof Lifecycle){
                Class<LifecycleListener> listenerClass = (Class<LifecycleListener>) Class.forName(host.getConfigClass());
                ((Lifecycle) context).addLifecycleListener(listenerClass.newInstance());
            }
            host.addChild(context);
        }catch (Exception e){
            host.log(sm.getString("standardHost.installError", contextPath), e);
            throw new IOException(e.toString());
        }
    }

    @Override
    public String[] findDeployedApps() {
        return Arrays.stream(host.findChildren()).map(Container::getName).toArray(String[]::new);
    }

    @Override
    public Context findDeployedApp(String contextPath) {
        return host.findChild(contextPath);
    }

    @Override
    public void remove(String contextPath) throws IOException{
        validateContext(contextPath, c -> c == null ? sm.getString("standardHost.pathMissing", contextPath) : null);
        host.log(sm.getString("standardHost.removing", contextPath));
        try {
            host.removeChild(findDeployedApp(contextPath));
        } catch (Exception e) {
            host.log(sm.getString("standardHost.removeError", contextPath), e);
            throw new IOException(e.toString());
        }
    }
}
